/**
 * @file cmd_at.c
 * @brief 
 * @author  ()
 * @version 1.0
 * @date 2024-09-13
 * 
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-13 <td>1.0     <td>     <td>内容
 * </table>
 */
#include "global.h"

#include "lettershell/shell.h"

#include "hal_adapter.h"

#include "bsp_wdt.h"
#include "bsp_adc.h"

#include "misc/misc_api.h"
#include "shell/shell_log.h"

/* Macro definition */
#define MAX_BUFF_SIZE 2048

#include "misc/hwmisc.h"
#include "mmgr/include/mmgr_modem.h"

#include "flash/protocol_params/protocol_params.h"
#include "comm/co_heartbeat.h"
#include "service/include/port/swei_wrapper.h"
#include "service/include/swei_cert.h"
#include "misc/misc_server.h"
#include "key_params/key_enc.h"
#include "service/include/swei_uplink.h"

extern int32_t load_quec_sn(char *sn, ssize_t len);

typedef struct cmd_list
{
    char *cmd;
    int32_t (*exec)(char *res, uint32_t res_len, int32_t argc, char *argv[]);
} cmd_list_t;

enum target
{
    IOT = 0,
    COMCU,
    BLE
};

enum cmd_res
{
    CMD_OK = 0,
    CMD_ERROR
};

/**
 * @brief 整机重启
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_reboot(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    if(argc <= 2)
        tbox_system_reboot(1000);
    else{
        if(argv[2][0] == '0'){
            tbox_system_reboot(1000);
        }else{
            swei_uplink_data_clear();
            tbox_system_reboot(1000);
        }
    }
        
    return SUCC;
}

/**
 * @brief 整机重启
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_restore(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    if(argc <= 2)
        tbox_system_restore(1000);
    else{
        if(argv[2][0] == '0'){
            tbox_system_restore(1000);
        }else{
            swei_uplink_data_clear();
            tbox_system_restore(1000);
        }
    }
        
    return SUCC;
}



/**
 * @brief 清除报文
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_clrdata(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    swei_uplink_data_clear();
    return SUCC;
}

/**
 * @brief 整机关机
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_shutdown(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    if(argc <= 2)
        tbox_system_poweroff(1000);
    else{
        if(argv[2][0] == '0'){
            tbox_system_poweroff(1000);
        }else{
            swei_uplink_data_clear();
            tbox_system_poweroff(1000);
        }
    }

    return SUCC;
}

int32_t dqa_wrprotect(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    return SUCC;
}

int32_t dqa_gpio(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    return SUCC;
}

#include "misc/hwmisc.h"
int32_t dqa_hw(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    if(res)
       snprintf(res, res_len, "%s", get_hw_ver());
    
    return SUCC;
}

#include "misc/version.h"
int32_t dqa_app(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    if(res)
       snprintf(res, res_len, "%s", SOFTWARE_VERSION);
    
    return SUCC;
}

/**
 * @brief 读取boot版本号
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_boot(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    if(res)
       snprintf(res, res_len, "%s", "unknown");
       
    return SUCC;
}

int32_t dqa_lp(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    return SUCC;
}

int32_t dqa_wd(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    int32_t target = -1;

    target = atoi(argv[2]);
    switch (target)
    {
        case IOT:
        {
            uint32_t status = 0;

            status = bsp_wdt_status();
            if(res)
                snprintf(res, res_len, "%d,%s", target, status ? "ENABLE" : "DISABLE");
        }
        break;
        case COMCU:
        case BLE:
        default:
            return -ENOEXEC;
    }

    return SUCC;
}

/**
 * @brief 读取IMEI参数
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_imei(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    const char *imei = mmgr_imei_get();

    if(strlen(imei)){
        if(res)
            snprintf(res, res_len, "%s", imei);
    }

    return SUCC;
}

#include "mmgr/include/mmgr_sim.h"

/**
 * @brief 读取ICCID参数
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_iccid(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    const char *iccid = mmgr_iccid_get();
    uint8_t stat = MMGR_SIM_UNKNOWN;

    if(MMGR_SIM_OK == (stat = mmgr_simcard_status_get())){
        if(strlen(iccid)){
            snprintf(res, res_len, "1,%s",iccid);
        }
    }else if (stat == MMGR_SIM_UNKNOWN) {
        snprintf(res, res_len, "-1");
    }else if (stat == MMGR_SIM_LOST) {
        snprintf(res, res_len, "0");
    }

    return SUCC;
}

// int32_t dqa_modemid(char *res, uint32_t res_len, int32_t argc, char *argv[])
// {
//     return SUCC;
// }

int32_t dqa_modem(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    const char *version = mmgr_version_get();

    if(strlen(version)){
        if(res)
            snprintf(res, res_len, "%s", version);
    }

    return SUCC;
}

// int32_t dqa_blemac(char *res, uint32_t res_len, int32_t argc, char *argv[])
// {
//     return SUCC;
// }

// int32_t dqa_can(char *res, uint32_t res_len, int32_t argc, char *argv[])
// {
//     return SUCC;
// }

/**
 * @brief 音频校验码查询
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_audio(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    return SUCC;
}

/**
 * @brief 电池电压
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_batvol(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    return SUCC;
}


/** 
 * @brief DQA命令设置SN AT+WSN="xxxxx"
 * @param  argc    传参个数
 * @param  argv    参数数组
 * @return char* 应答字段 +ACK:SN,OK
 */
int32_t dqa_wsn(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    if(argc > 1)
    {
        if(argv[2]) {
            tbox_set_sn(argv[2]);
            if(res)
                snprintf(res, res_len, "%s", argv[2]);
        } else {
            tbox_clr_sn();
        }

        return SUCC;
    }

    return ENOEXEC;
}

/**
 * @brief DQA命令查询SN, AT+RSN     
 * @param  res              指令命令返回值
 * @param  res_len          返回值长度
 * @param  argc             命令参数个数
 * @param  argv             命令参数数组
 * @return int32_t 
 */
int32_t dqa_rsn(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    char sn[32] = {0};
    char yw_sn[32] = {0};

    load_quec_sn(yw_sn, sizeof(yw_sn));
    config_get(CONFIG_ID_SN, sn);

    if(res)
    {
        snprintf(res, res_len, ",%s,%s", yw_sn, sn);
    }

    return SUCC;
}

// int32_t dqa_entrance(char *res, uint32_t res_len, int32_t argc, char *argv[])
// {
//     return SUCC;
// }

/* optional */
int32_t dqa_gpsstats(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    // +GPSSTATSS:OK,${loc},{num}<,cnlist[0]...cnlist[num]>
    // if(res)
    //     snprintf(res, res_len, "", );
    return SUCC;
}


#include "mmgr/include/mmgr_misc.h"
/**
 * @brief 查询网络注册状态
 * @return int32_t 
 */
int32_t dqa_netstats(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    int32_t net_status = 0;
    int32_t rat_state = 0;
    // +NETSTATS:OK,${net_status},${rat_state}
    const char *net_status_str[] = {"NO", "OK[HOME]", "OK[ROAMING]", "UNKNOWN"};
    const char *rat_state_str[] = {"AUTO", "2G", "3G", "4G", "EMTC", "NBIoT", "UNKNOWN"};
    
    if(res){
        if(0 == modem_get_netreg_status(&net_status, &rat_state)){
            snprintf(res, res_len, "%s,%s", net_status_str[net_status], rat_state_str[rat_state]);
        }else{
            snprintf(res, res_len, "%s", net_status_str[sizeof(net_status_str) / sizeof(char *) - 1]);
            return -ENETUNREG;
        }
    }
        
    return SUCC;

}

/**
 * @brief 设置/查询服务器地址
 * @return int32_t SUCC - 设置或者查询成功
 */
int32_t dqa_server(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    server_params_t server = {0};

    if (argc > 2) { // AT+SERVER=ip,port
        misc_server_param_get(&server);
        if (argc >= 4) { // AT+SERVER="ip",port
            snprintf(server.ipaddr, sizeof(server.ipaddr), "%s", argv[2]);
            server.port = atoi(argv[3]);
            server.enable = 1;
            if(0 == strcmp(server.ipaddr, "218.17.50.142") || 0 == strcmp(server.ipaddr, "183.56.181.58")) {
                server.is_ssl = 0;
            } else {
                if (strlen(misc_ssl_cacert_get()) > 0) {
                    server.is_ssl = 1;
                }

            }
            misc_server_param_set(&server);
        }
        // set the server param, AT+SERVER="ip",port,"cert"
        if (res) {
            snprintf(res, res_len, "%s,%d", server.ipaddr, server.port);
        }
    } else if(argc == 2) {
        // require the server param, AT+SERVER?
        misc_server_param_get(&server);
        if(res) {
            snprintf(res, res_len, "%s,%d(ssl:%s)", server.ipaddr, server.port, server.is_ssl ? "yes" : "no");
        }
    }

    return SUCC;
}


#include "task_gnss.h"
#include "mmgr/include/mmgr_modem.h"

/**
 * @brief 查询软件版本，IoT仅支持AT+SWVER=IoT/MODEM/GPS
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_swver(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    if (argc >= 3) {
        if (0 == strcmp(argv[2], "IoT")) {
            snprintf(res, res_len, "%s", SOFTWARE_VERSION);
        } else if (0 == strcmp(argv[2], "MODEM")) {
            snprintf(res, res_len, "%s", mmgr_subversion_get());
        } else if (0 == strcmp(argv[2], "GPS")) {
            /* gps_ver */
            char gps_ver[GNSS_FW_VER_LEN + 1] = {0};
            qltask_gnss_firmware_version(gps_ver, sizeof(gps_ver));
            snprintf(res, res_len, "%s", gps_ver);
        }
    }

    return SUCC;
}


/**
 * @brief 查询硬件版本，IoT仅支持AT+HWVER=IoT
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_hwver(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    if(res)
        snprintf(res, res_len, "%s", get_hw_ver());

    return SUCC;
}

int32_t dqa_switch(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    if(argc >= 3)
    {
        if (0 == strcmp(argv[2], "enable")) {
            tbox_dqa_mode_set(1);
        } else if (0 == strcmp(argv[2], "disable")) {
            tbox_dqa_mode_set(0);
        }

        if(res)
            snprintf(res, res_len, "%s", tbox_dqa_mode_get() ? "enable" : "disable");
    } else if (argc == 2) {
        if (res)
            snprintf(res, res_len, "%s", tbox_dqa_mode_get() ? "enable" : "disable");
    }

    return SUCC;
}


/**
 * @brief QFCT指令处理
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_fct(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    if(argc == 3)
    {
        if (0 == strcmp(argv[2], "0201")) {
            char yw_sn[32] = {0};

            load_quec_sn(yw_sn, sizeof(yw_sn));
            printf("+SN:%s\r\nOK\r\n", yw_sn);
        }

        return SUCC;
    }


    return ENOEXEC;
}



/**
 * @brief enc指令处理
 * @param  res              My Param doc
 * @param  res_len          My Param doc
 * @param  argc             My Param doc
 * @param  argv             My Param doc
 * @return int32_t 
 */
int32_t dqa_enc(char *res, uint32_t res_len, int32_t argc, char *argv[])
{
    char key_array[32] = {0};

    if(argc >= 3 && argv[2] != 0)
    {
        qltask_modem_fw_encryption_key_set((char *)argv[2], strlen(argv[2]));
        qltask_modem_fw_encryption_key_get((char *)key_array, sizeof(key_array) - 1);
        if (res)
            snprintf(res, res_len, "%s", key_array);
        
        return SUCC;
    } else if (argc == 2) {
        qltask_modem_fw_encryption_key_get((char *)key_array, sizeof(key_array) - 1);
        if (res)
            snprintf(res, res_len, "%s", key_array);
        
        return SUCC;
    }
    
    return ENOEXEC;
}


static const cmd_list_t cmd_tab[] = {
    {"REBOOT", dqa_reboot},
    {"RESTORE", dqa_restore},
    {"CLRDATA", dqa_clrdata},
    {"SHUTDOWN", dqa_shutdown},
    {"WRPROTECT", dqa_wrprotect},
    {"GPIO", dqa_gpio},
    {"HW", dqa_hw},
    {"APP", dqa_app},
    {"BOOT", dqa_boot},
    {"LP", dqa_lp},
    {"WD", dqa_wd},
    {"IMEI", dqa_imei},
    {"ICCID", dqa_iccid},
    // {"MODEMID", dqa_modemid},
    {"MODEM", dqa_modem},
    // {"BLEMAC", dqa_blemac},
    // {"CAN", dqa_can},
    {"AUDIO", dqa_audio},
    {"WSN", dqa_wsn},
    {"RSN", dqa_rsn},
    // {"DQA", dqa_entrance},
    /* optional */
    {"GNSSTATS", dqa_gpsstats},
    {"NETSTATS", dqa_netstats},
    {"SERVER", dqa_server},
    {"SWVER", dqa_swver},
    {"HWVER", dqa_hwver},
    {"DQA", dqa_switch},
    {"BATVOL", dqa_batvol},
    {"QFCT", dqa_fct},
    {"ENC", dqa_enc},
};

extern const char *errno_str(int errno);
/**
 * @brief AT命令解析函数
 * @param  argc             入参个数
 * @param  argv             入参数组
 * @return int32_t 0 - at命令解析成功
 */
int32_t at_cmd_parser(int32_t argc, char *argv[])
{
    char res[MAX_BUFF_SIZE + 1] = {0};
    int32_t errno = ENOEXEC;

    for (int32_t i = 0; i < sizeof(cmd_tab) / sizeof(cmd_tab[0]); i++)
    {
        if (strcmp(argv[1], cmd_tab[i].cmd) == 0)
        {
            errno = cmd_tab[i].exec(res, sizeof(res), argc, argv);
            break;
        }
    }

    if (SUCC == errno)
        printf("+%s:OK,%s\r\n", argv[1], res);
    else 
        printf("+%s,ERROR:%d,%s\r\n", argv[1], errno, errno_str(errno));

    return 0;
}

SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_DISABLE_RETURN,
                 AT, at_cmd_parser, AT command);
